package com.pig4cloud.pigx.gateway;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HexUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

@Slf4j
public class CustomDecoder extends ByteToMessageDecoder {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(CustomDecoder.class);
    private final byte DELIMITER = 0x7E;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 查找分隔符的位置
//        int delimiterIndex = in.bytesBefore(DELIMITER);
//        // 如果找到了分隔符
//        if (delimiterIndex != -1) {
//            // 跳过分隔符之前的数据
//            in.skipBytes(delimiterIndex);
//
//            // 检查是否有足够的字节可供读取
//            if (in.readableBytes() >= 2) { // 至少要有两个字节表示数据长度
//                // 读取数据长度
//                int readableBytes = in.readableBytes();
//                log.info("数据长度:{}",readableBytes);
////                // 判断是否有足够的字节可供读取以读取整个数据内容
////                if (in.readableBytes() >= dataLength) {
//                    // 读取实际数据部分
//                    byte[] data = new byte[readableBytes];
//                    in.readBytes(data);
//                    out.add(data);
//                    // 打印字节数组的十六进制表示
//                    logger.info("Received message with delimiter: {}", data);
////                } else {
////                    // 如果没有足够的字节可供读取以读取整个数据内容，则重置读取位置，等待更多数据到达
////                    in.readerIndex(delimiterIndex); // 重置读取位置
////                }
//            } else {
//                // 如果没有足够的字节可供读取，则重置读取位置，等待更多数据到达
//                in.readerIndex(delimiterIndex); // 重置读取位置
//            }
//        } else {
//            // 如果没有找到分隔符，则清空缓冲区
//            in.clear();
//        }

        int delimiterIndex = in.indexOf(in.readerIndex(), in.writerIndex(), DELIMITER);
        int readableBytes = in.readableBytes();
        log.info("总的长度:{}",readableBytes);
        // 如果没有找到 0x7E，则返回
        if (delimiterIndex == -1) {
            return;
        }
        // 读取到 0x7E 的索引位置
        in.skipBytes(delimiterIndex - in.readerIndex());
        // 读取实际数据部分的长度
        int dataLength = ((in.getByte(in.readerIndex() + 1) & 0xFF) << 8) | (in.getByte(in.readerIndex() + 2) & 0xFF);
        log.info("数据长度:{}",dataLength);

        // 读取 0x7E 后面的数据
        ByteBuf frame = in.readSlice(in.readableBytes());
        // 将 ByteBuf 转换为字节数组
        byte[] data = new byte[frame.readableBytes()];
        log.info("后面报文长度的:{}",data.length);
        frame.readBytes(data);
        // 添加字节数组到输出列表
        out.add(data);
        logger.info("Received message with delimiter: {}", data);
    }

    // 辅助方法：将字节数组转换为十六进制字符串表示
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    private int calculateMessageLength(ByteBuf in) {
        // 读取两个字节作为长度，并调整为实际需要读取的长度
        return in.readUnsignedShort(); // 加上起始字节的长度
    }

    /**
     * 将十进制数转换为指定位数的十六进制字符串表示，并补零到指定位数。
     *
     * @param decimal   十进制数
     * @param hexDigits 目标十六进制位数
     * @return 补零后的十六进制字符串
     */
    public static String decimalToHex(int decimal, int hexDigits) {
        // 使用 Integer 类的静态方法将十进制数转换为十六进制字符串
        String hex = Integer.toHexString(decimal).toUpperCase();

        // 计算需要补零的位数
        int zeroPadding = hexDigits - hex.length();

        // 在十六进制字符串前补零
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < zeroPadding; i++) {
            result.append("0");
        }
        result.append(hex);

        return result.toString();
    }

    public static void main(String[] args) {
        String respString = "0103020153F9E9";
        byte[] respData = hexStringToByteArray(respString);
//        int decimalNumber = hex2decimal(hexString);
//        System.out.println(hexString + " 的十进制表示为 " + decimalNumber);
//
//        float valtage = (float) hex2decimal("00231860");
//        System.out.println("电压" + valtage * 0.0001);


//        byte[] dataByte = new byte[2];
//        System.arraycopy(data, 3, dataByte, 0, dataByte.length);
//        String dataHexString = HexUtil.encodeHexStr(dataByte);
//        log.info("数据数组:{}",dataByte);
//        log.info("数据十六进制报文:{}",dataHexString);
//        int decimalNumber = hex2decimal(dataHexString);
//        System.out.println(dataHexString + " 的十进制表示为 " + decimalNumber);


        // 从机地址
        String address = "01";
        // 功能码，读取保持寄存器
        String code = "03";
        // 开始位置 201
        String[] start = {"00", "65"};
        // 数据长度，读取1位
        String[] length = {"00", "01"};
        // 计算CRC，得出完整消息
        byte[] sendData = getData(address, code, start[0], start[1], length[0], length[1]);
        log.info("发送命令数组:{}",sendData);
        String sendHexString = HexUtil.encodeHexStr(sendData);
        log.info("发送命令十六进制字符串:{}",sendHexString);
        ByteBuf byteBuf = Unpooled.buffer();
        byteBuf.writeBytes(sendData);


        int decimalNumber = 3;
        int hexDigits = 2;
        String hexString = decimalToHex(decimalNumber, hexDigits);
        System.out.println("补零后的十六进制表示为：" + hexString);

//        log.info("报文数组:{}",data);
//
//        log.info("报文长度:{}",data.length);
//
//        log.info("设备报文:{}", HexUtil.encodeHexStr(data));

        //处理粘包
//        for (int i = 0; i < data.length; i++) {
//            byte datum = data[i];
//            if (datum != 0x7e) continue;
//            if (i == 0) break;
//            byte[] temp = new byte[data.length - i];
//            System.arraycopy(data, i, temp, 0, data.length - i);
//            data = temp;
//            break;
//        }
//
//        log.info("处理后的内容:{}",data);
//
//        byte frameHeader = data[0];
//        if (frameHeader != 0x7E) {
//            log.error("报文不合法,帧头:{}", HexUtil.toHex(frameHeader));
//        }
//        //从帧类型开始，到数据段结束的所有字节数
//        byte[] dataLength = new byte[2];
//        System.arraycopy(data, 1, dataLength, 0, 2);
//        int length = ((dataLength[dataLength[0]]) << 8) | (byte2Hex(dataLength[1]));
//		log.info("数据段长度：{}", length);
//        //帧类型到数据段的长度
//        int frameType2DataSegment = length - 12;
//		log.info("帧类型到数据段的长度：{}    {}", dataLength, HexUtil.toHex(length));
//        byte[] macAddress = new byte[8];
//        System.arraycopy(data, 4, macAddress, 0, 8);
//        String macStr = HexUtil.encodeHexStr(macAddress);
//        log.info("安帕尔私有协议设备MAC:{}", macStr);
//        byte[] dataSegment = new byte[frameType2DataSegment];
//        System.arraycopy(data, 15, dataSegment, 0, frameType2DataSegment);
//        log.info("数据内容:{}", HexUtil.encodeHexStr(dataSegment));
//
//
//        //读取的索引
//        Integer readIndex;
//        byte dateFrameHeader = dataSegment[0];
//        if (byte2Hex(dateFrameHeader) != 0xAA) {
//            log.error("数据段帧头错误:{}", HexUtil.toHex(byte2Hex(dateFrameHeader)));
//        }
//
//        byte deviceProperties = dataSegment[4];
//        log.info("设备属性:{}", HexUtil.toHex(byte2Hex(deviceProperties)));
//        byte protocolVersion = dataSegment[5];
//        log.info("协议版本:{}", HexUtil.toHex(byte2Hex(protocolVersion)));
//        byte[] alarmInfo = new byte[2];
//        System.arraycopy(dataSegment, 6, alarmInfo, 0, alarmInfo.length);
//        ArrayUtil.swap(alarmInfo, 0, 1);
//        log.info("报警数组:{}",alarmInfo);
//        // 该项置位为发生报警，置零为该项未报警。多种报警信息并存支持，2 字节。部分功能为预留功能。
//        // 常见的有：00 00 正常；01 00 低报警；02 00 高报警；04 00 超量程
//        int value = ((alarmInfo[0] & 0xFF) << 8) | (alarmInfo[1] & 0xFF);
//        log.info("报警信息:{}", String.format("0x%04X", value));
//        byte[] timeStamp = new byte[6];
//        System.arraycopy(dataSegment, 8, timeStamp, 0, timeStamp.length);
//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMddHHmmss");
//        LocalDateTime receptionTime = LocalDateTime.parse(HexUtil.encodeHexStr(timeStamp), formatter);
//        log.info("时间戳:{},{}", HexUtil.encodeHexStr(timeStamp), receptionTime);
//        byte numberData = dataSegment[14];
//        log.info("数据个数:{}", HexUtil.toHex(byte2Hex(numberData)));
//        readIndex = 15;
//        for (int i = 0; i < numberData; i++) {
//            byte[] gasTypeIdAndUnit = new byte[2];
//            readIndex = copyAndMoveReadIndexOrder(dataSegment, readIndex, gasTypeIdAndUnit);
//            log.info("气体类型单位数组:{}",gasTypeIdAndUnit);
//            log.info("气体类型和单位:0x{}", HexUtil.encodeHexStr(gasTypeIdAndUnit));
//            byte[] val = new byte[4];
//            readIndex = copyAndMoveReadIndex(dataSegment, readIndex, val);
//            String vatStr = HexUtil.encodeHexStr(val);
//            log.info("气体值数组:{}",val);
//            float gasValFloat = ByteBuffer.wrap(val).order(ByteOrder.LITTLE_ENDIAN).getFloat() ;
//            DecimalFormat df = new DecimalFormat("#.###");
//            String gasVal = df.format(gasValFloat);
//            ArrayUtil.swap(gasTypeIdAndUnit, 0, 1);
//            log.info("气体类型单位数组转换后:{}",gasTypeIdAndUnit);
//            value = ((gasTypeIdAndUnit[0] & 0xFF) << 8) | (gasTypeIdAndUnit[1] & 0xFF);
//            int typeId = value & 0xFFF;
//            int unitId = (value >> 12) & 0xF;
//            String gasType = String.format("0x%04X", typeId);
//            String gasUnit = String.format("0x%02X", unitId);
//
//            log.info("气体类型:{}",gasType);
//            log.info("单位:{},",gasUnit);
//            log.info("值:0x{},{}", vatStr, gasVal);
//        }

    }

    /**
     * 获取源数据和验证码的组合byte数组
     *
     * @param strings 可变长度的十六进制字符串
     * @return
     */
    public static byte[] getData(String... strings) {
        byte[] data = new byte[]{};
        for (int i = 0; i < strings.length; i++) {
            int x = Integer.parseInt(strings[i], 16);
            byte n = (byte) x;
            byte[] buffer = new byte[data.length + 1];
            byte[] aa = {n};
            System.arraycopy(data, 0, buffer, 0, data.length);
            System.arraycopy(aa, 0, buffer, data.length, aa.length);
            data = buffer;
        }
        return getData(data);
    }

    /**
     * 获取源数据和验证码的组合byte数组
     *
     * @param aa 字节数组
     * @return
     */
    private static byte[] getData(byte[] aa) {
        byte[] bb = getCrc16(aa);
        byte[] cc = new byte[aa.length + bb.length];
        System.arraycopy(aa, 0, cc, 0, aa.length);
        System.arraycopy(bb, 0, cc, aa.length, bb.length);
        return cc;
    }

    /**
     * 获取验证码byte数组，基于Modbus CRC16的校验算法
     */
    private static byte[] getCrc16(byte[] arr_buff) {
        int len = arr_buff.length;

        // 预置 1 个 16 位的寄存器为十六进制FFFF, 称此寄存器为 CRC寄存器。
        int crc = 0xFFFF;
        int i, j;
        for (i = 0; i < len; i++) {
            // 把第一个 8 位二进制数据 与 16 位的 CRC寄存器的低 8 位相异或, 把结果放于 CRC寄存器
            crc = ((crc & 0xFF00) | (crc & 0x00FF) ^ (arr_buff[i] & 0xFF));
            for (j = 0; j < 8; j++) {
                // 把 CRC 寄存器的内容右移一位( 朝低位)用 0 填补最高位, 并检查右移后的移出位
                if ((crc & 0x0001) > 0) {
                    // 如果移出位为 1, CRC寄存器与多项式A001进行异或
                    crc = crc >> 1;
                    crc = crc ^ 0xA001;
                } else
                    // 如果移出位为 0,再次右移一位
                    crc = crc >> 1;
            }
        }
        return intToBytes(crc);
    }

    /**
     * 将int转换成byte数组，低位在前，高位在后
     * 改变高低位顺序只需调换数组序号
     */
    private static byte[] intToBytes(int value) {
        byte[] src = new byte[2];
        src[1] = (byte) ((value >> 8) & 0xFF);
        src[0] = (byte) (value & 0xFF);
        return src;
    }


    // 16进制转换10进制
    public static int hex2decimal(String hex) {
        return Integer.parseInt(hex, 16);
    }


    /**
     * 正常复制
     */
    public static Integer copyAndMoveReadIndex(byte[] src, Integer readIndex, byte[] target) {
        System.arraycopy(src, readIndex, target, 0, target.length);
        return readIndex + target.length;
    }

    /**
     * 大小端转换
     */
    public static Integer copyAndMoveReadIndexOrder(byte[] src, Integer readIndex, byte[] target) {
        System.arraycopy(src, readIndex, target, 0, target.length);
        target = ByteBuffer.wrap(target).order(ByteOrder.LITTLE_ENDIAN).array();
        return readIndex + target.length;
    }

    public static int calculateLength(byte[] bytes) {
        if (bytes.length != 2) {
            throw new IllegalArgumentException("The input byte array must contain exactly two bytes.");
        }

        // 将字节数组中的两个字节转换为十进制数值，并组合起来计算长度
        int length = (bytes[0] & 0xFF) << 8 | (bytes[1] & 0xFF);
        return length;
    }

    public static int byte2Hex(byte b) {
        return b & 0XFF;
    }

    public static byte[] hexStringToByteArray(String hexString) {
        int length = hexString.length();
        byte[] byteArray = new byte[length / 2];
        for (int i = 0; i < length; i += 2) {
            byteArray[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return byteArray;
    }

}